package com.opencee.cloud.base.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.opencee.boot.db.mybatis.service.impl.SupperServiceImpl;
import com.opencee.cloud.base.constants.BaseConstants;
import com.opencee.cloud.base.constants.BaseGrantToType;
import com.opencee.cloud.base.constants.BaseResourceType;
import com.opencee.cloud.base.entity.BaseApiEntity;
import com.opencee.cloud.base.entity.BaseMenuEntity;
import com.opencee.cloud.base.entity.BasePrivilegesEntity;
import com.opencee.cloud.base.mapper.BasePrivilegesMapper;
import com.opencee.cloud.base.service.IBaseApiService;
import com.opencee.cloud.base.service.IBaseMenuService;
import com.opencee.cloud.base.service.IBasePrivilegesService;
import com.opencee.cloud.base.vo.BaseApiVO;
import com.opencee.cloud.base.vo.BaseMenuVO;
import com.opencee.cloud.base.vo.params.BaseGrantParams;
import com.opencee.common.exception.BaseFailException;
import com.opencee.common.security.SecurityHelper;
import com.opencee.common.security.SecurityUser;
import com.opencee.common.utils.RedisTemplateUtil;
import com.opencee.common.utils.WebUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 资源授权 服务实现类
 * </p>
 *
 * @author liuyadu
 * @since 2021-04-16
 */
@Service
public class BasePrivilegesServiceImpl extends SupperServiceImpl<BasePrivilegesMapper, BasePrivilegesEntity> implements IBasePrivilegesService {
    @Autowired
    private IBaseMenuService menuService;
    @Autowired
    private IBaseApiService apiService;
    @Autowired
    private RedisTemplateUtil redisTemplateUtil;

    /**
     * 保存权限
     *
     * @param grant
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void grantSave(BaseGrantToType grantToType, BaseResourceType resourceType, BaseGrantParams grant) {
        if ((grantToType.equals(BaseGrantToType.ROLE) && grant.getGrantToId() == 1L)) {
            throw new BaseFailException("超级管理员禁止授权");
        }
        // 先移除后添加
        this.removeBy(grantToType, resourceType, grant.getGrantToId());
        this.grantAdd(grantToType, resourceType, grant);
    }

    /**
     * 添加授权
     *
     * @param grant
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void grantAdd(BaseGrantToType grantToType, BaseResourceType resourceType, BaseGrantParams grant) {
        if ((grantToType.equals(BaseGrantToType.ROLE.getValue()) && grant.getGrantToId() == 1L)) {
            throw new BaseFailException("超级管理员禁止授权");
        }
        if (CollectionUtils.isEmpty(grant.getGrantResIds())) {
            return;
        }
        List<BasePrivilegesEntity> list = grant.getGrantResIds().stream().filter(t -> {
            return !exists(grantToType, resourceType, grant.getGrantToId(), t);
        }).map(t -> {
            BasePrivilegesEntity entity = new BasePrivilegesEntity();
            entity.setGrantResId(t);
            entity.setGrantResType(resourceType.getValue());
            entity.setEndTime(grant.getEndTime());
            entity.setStartTime(grant.getStartTime());
            entity.setGrantToId(grant.getGrantToId());
            entity.setGrantToType(grantToType.getValue());
            if (BaseGrantToType.BTN.equals(grantToType)) {
                // 更新用户操作权限缓存
                BaseMenuEntity baseMenuEntity = menuService.getById(entity.getGrantResId());
                BaseMenuEntity grantToEntity = menuService.getById(entity.getGrantToId());
                String key = baseMenuEntity.getPath() + BaseConstants.SEPARATOR + baseMenuEntity.getSid();
                Set<String> permission = (Set<String>) redisTemplateUtil.hget(BaseConstants.CACHE_RESOURCES_GRANTED_AUTHORITY_KEY, key);
                if (permission == null) {
                    permission = new HashSet<>();
                }
                permission.add(grantToEntity.getAuthority());
                redisTemplateUtil.hset(BaseConstants.CACHE_RESOURCES_GRANTED_AUTHORITY_KEY, key, permission);
            }
            return entity;
        }).collect(Collectors.toList());
        if (!list.isEmpty()) {
            // 批量保存
            super.saveBatch(list);
        }
    }

    /**
     * 移除授权
     *
     * @param grant
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void grantRemove(BaseGrantToType grantToType, BaseResourceType resourceType, BaseGrantParams grant) {
        if ((grantToType.equals(BaseGrantToType.ROLE.getValue()) && grant.getGrantToId() == 1L)) {
            throw new BaseFailException("超级管理员禁止授权");
        }
        if (CollectionUtils.isEmpty(grant.getGrantResIds())) {
            return;
        }
        QueryWrapper<BasePrivilegesEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(BasePrivilegesEntity::getGrantToId, grant.getGrantToId())
                .eq(BasePrivilegesEntity::getGrantToType, grantToType.getValue())
                .in(BasePrivilegesEntity::getGrantResId, grant.getGrantResIds());
        this.remove(wrapper);
        if (BaseGrantToType.BTN.equals(grantToType)) {
            // 更新用户操作权限缓存
            BaseMenuEntity grantToEntity = menuService.getById(grant.getGrantToId());
            grant.getGrantResIds().forEach(t -> {
                BaseMenuEntity baseMenuEntity = menuService.getById(t);
                String key = baseMenuEntity.getPath() + BaseConstants.SEPARATOR + baseMenuEntity.getSid();
                Set<String> permission = (Set<String>) redisTemplateUtil.hget(BaseConstants.CACHE_RESOURCES_GRANTED_AUTHORITY_KEY, key);
                if (permission == null) {
                    permission = new HashSet<>();
                }
                permission.remove(grantToEntity.getAuthority());
                redisTemplateUtil.hset(BaseConstants.CACHE_RESOURCES_GRANTED_AUTHORITY_KEY, key, permission);
            });
        }
    }

    /**
     * 检查是否已存在
     *
     * @param grantToType
     * @param grantToId
     * @param grantId
     * @return
     */
    @Override
    public boolean exists(BaseGrantToType grantToType, BaseResourceType resourceType, Long grantToId, Long grantId) {
        QueryWrapper<BasePrivilegesEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(BasePrivilegesEntity::getGrantResType, resourceType.getValue())
                .eq(BasePrivilegesEntity::getGrantResId, grantId)
                .eq(BasePrivilegesEntity::getGrantToId, grantToId)
                .eq(BasePrivilegesEntity::getGrantToType, grantToType.getValue());
        return super.count(wrapper) > 0;
    }

    /**
     * 批量移除授权
     *
     * @param grantToType
     * @param grantToId
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeBy(BaseGrantToType grantToType, BaseResourceType resourceType, Long grantToId) {
        QueryWrapper<BasePrivilegesEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(BasePrivilegesEntity::getGrantResType, resourceType.getValue())
                .eq(BasePrivilegesEntity::getGrantToId, grantToId)
                .eq(BasePrivilegesEntity::getGrantToType, grantToType.getValue());
        return super.remove(wrapper);
    }

    /**
     * 移除资源授权
     *
     * @param rids
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeByGrantIds(BaseResourceType resourceType, Set<Long> rids) {
        if (CollectionUtils.isEmpty(rids)) {
            return false;
        }
        QueryWrapper<BasePrivilegesEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(BasePrivilegesEntity::getGrantResType, resourceType.getValue())
                .in(BasePrivilegesEntity::getGrantResId, rids);
        return super.remove(wrapper);
    }

    /**
     * 查询角色已授权功能菜单
     *
     * @param sid     系统ID
     * @param roleIds
     * @param valid   有效的
     * @return
     */
    @Override
    public List<BaseMenuVO> listRoleGrantedMenu(String sid, Set<Long> roleIds, Boolean valid) {
        Map<String, Object> map = new HashMap<>(8);
        // 角色为超管的查询全部
        if (roleIds.contains(1L)) {
            List<BaseMenuVO> list = menuService.list(sid, 1);
            return list;
        }
        map.put("sid", sid);
        map.put("grantToType", BaseGrantToType.ROLE.getValue());
        map.put("grantToIds", roleIds);
        map.put("valid", valid);
        return baseMapper.selectGrantedMenu(map);
    }

    /**
     * 查询操作项关联接口
     *
     * @param btnId 应用ID
     * @return
     */
    @Override
    public List<BaseApiVO> listBtnGrantedApi(Long btnId, Boolean valid) {
        Map<String, Object> map = new HashMap<>(8);
        map.put("grantToType", BaseGrantToType.BTN.getValue());
        map.put("grantToIds", Arrays.asList(btnId));
        map.put("valid", valid);
        return baseMapper.selectGrantedApi(map);
    }

    /**
     * 查询已授权API接口
     *
     * @param appId
     * @param valid 有效的
     * @return
     */
    @Override
    public List<BaseApiVO> listAppGrantedApi(Long appId, Boolean valid) {
        Map<String, Object> map = new HashMap<>(8);
        map.put("grantToType", BaseGrantToType.APP.getValue());
        map.put("grantToIds", Arrays.asList(appId));
        map.put("valid", valid);
        return baseMapper.selectGrantedApi(map);
    }


    /**
     * 访问接口权限验证
     *
     * @param path
     * @param sid
     * @return
     */
    @Override
    public boolean accessApiValid(String path, String sid) throws NoHandlerFoundException {
        boolean permit = false;
        String key = path + BaseConstants.SEPARATOR + sid;
        BaseApiEntity baseApiEntity = apiService.getByPath(path, sid);
        if (baseApiEntity == null) {
            HttpServletRequest request = WebUtil.getHttpServletRequest();
            HttpHeaders httpHeaders = new HttpHeaders();
            throw new NoHandlerFoundException(request.getMethod(), request.getRequestURI(), httpHeaders);
        }
        SecurityUser user = SecurityHelper.getUser();
        Set<String> permission = (Set<String>) redisTemplateUtil.hget(BaseConstants.CACHE_RESOURCES_GRANTED_AUTHORITY_KEY, key);
        if (CollectionUtils.isEmpty(permission)) {
            return false;
        }
        if (user.isClientOnly()) {
            // 客户端访问

        } else {
            // 用户访问
        }
        return permit;
    }

    /**
     * 初始化权限
     */
    @PostConstruct
    @Override
    public void init() {
/*        List<BaseMenuVO> userPermissionList = baseMapper.selectAllGrantedMenu();
        Map<Long, List<BaseMenuVO>> map = userPermissionList.stream().collect(Collectors.groupingBy(BaseMenuVO::getId));
        Map<String, Set<String>> permissionMap = new HashMap<>(6);
        for (Map.Entry<Long, List<BaseMenuVO>> entry : map.entrySet()) {
            List<BaseMenuVO> value = entry.getValue();
            if (CollectionUtils.isEmpty(value)) {
                continue;
            }
            BaseMenuVO vo = value.get(0);
            Set<String> authorities = value.stream().map(t -> t.getGrantToAuthority()).collect(Collectors.toSet());
            String key = vo.getPath() + BaseConstants.SEPARATOR + vo.getSid();
            permissionMap.put(key, authorities);
        }
        redisTemplateUtil.setMap(BaseConstants.CACHE_RESOURCES_GRANTED_AUTHORITY_KEY, permissionMap);*/
    }
}
